﻿using EMall.Query;
using Microsoft.EntityFrameworkCore;
using System.Text;
using Yarp.ReverseProxy.Configuration;

namespace EMall.AdminGateway
{
    public interface IYarpProxyConfigStore
    {
        Task<IProxyConfig> GetConfigAsync();
    }
    public class YarpProxyConfigStore : IYarpProxyConfigStore
    {
        private readonly IQueryService _queryService;
        public YarpProxyConfigStore(IQueryService queryService)
        {
            _queryService = queryService;
        }
        public async Task<IProxyConfig> GetConfigAsync()
        {
            var newConfig = new YarpProxyConfig();
            try
            {
                var apiResources = (await _queryService.GetQueryable<IdentityServer4.EntityFramework.Entities.ApiResource>()
                    .Include(x => x.Secrets)
                    .Include(x => x.Scopes)
                    .Include(x => x.UserClaims)
                    .Include(x => x.Properties)
                    .ToListAsync())
                    .Select(o => o.ToModel());
                foreach (var apiResource in apiResources)
                {
                    var destinations = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase);
                    var urls = apiResource.Properties.FirstOrDefault(o => o.Key == "Destinations").Value.Split(',');
                    for (int i = 0; i < urls.Length; i++)
                    {
                        destinations.Add($"destination{i + 1}", new DestinationConfig { Address = urls[i] });
                    }
                    var clusterConfig = new ClusterConfig
                    {
                        ClusterId = apiResource.Name,
                        Destinations = destinations,
                    };
                    newConfig.AddClusters(clusterConfig);
                    var routePrefix = apiResource.Name + "/api";
                    if (apiResource.Scopes.Any())
                    {
                        foreach (var scope in apiResource.Scopes)
                        {
                            var routePath = new StringBuilder("/" + routePrefix);
                            var scopeArrary = scope.Replace(apiResource.Name + ".", "").Split('.');
                            if (scopeArrary.Length > 0)
                            {
                                if (scopeArrary.Length == 1)
                                {
                                    routePath.Append("/").Append(scopeArrary[0]).Append("/{**everything}");
                                }
                                else
                                {
                                    foreach (var item in scopeArrary)
                                    {
                                        routePath.Append("/").Append(item);
                                    }
                                    //routePath.Append("{**everything}");
                                }
                                var routeConfig = new RouteConfig()
                                {
                                    RouteId = $"{scope}",
                                    ClusterId = clusterConfig.ClusterId,
                                    Match = new RouteMatch
                                    {
                                        Path = routePath.ToString()
                                    }
                                };
                                newConfig.AddRoutes(routeConfig);
                            }
                        }
                    }
                    else
                    {
                        var routeConfig = new RouteConfig()
                        {
                            RouteId = $"{apiResource.Name}",
                            ClusterId = clusterConfig.ClusterId,
                            Match = new RouteMatch
                            {
                                Path = "/" + routePrefix + "/{**everything}"
                            }
                        };
                        newConfig.AddRoutes(routeConfig);
                    }
                }
            }
            catch (Exception)
            {

            }
            return newConfig;
        }
    }
}
